home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Sherlock 2.0
/
DevLibSrc
/
Main_DevLib
/
LIBenv.c
< prev
next >
Wrap
Text File
|
1995-10-28
|
12KB
|
558 lines
/*
devlib: environment module.
source: LIBenv.c
started: November 4, 1993.
version:
October 26, 1995
Changes made to support new Universal Headers.
January 7, 1994.
*/
#include <LIBlib.h>
#include <LIBenv.h>
#include <LIBlist.h>
/*
Only a dummy env_dump_stats is compiled unless THINK_C is #defined.
*/
#ifdef THINK_C
// Can't be used with Universal headers
// #include <LoMem.h>
// From <LoMem.h>: Warning: can't be used on a Power Mac.
#define Declare_LoMem(type, name, address) type (name) : (address)
Declare_LoMem(THz, ApplZone, 0x2AA);
#endif
#if defined(THINK_C)
#include <Errors.h>
#include <Memory.h>
#include <Resources.h>
#include <Types.h>
typedef struct code_struct code_info;
static struct code_struct {
TYPE_LIST(code_info);
int code_ID;
long code_tag;
long code_addr;
long code_checkSum;
};
static code_info * old_code_info_list = NULL;
static code_info * new_code_info_list = NULL;
/*
Declare internal routines.
*/
static code_info * env_checkSum (void);
static void * env_compare (code_info * n1, code_info * n2);
static void env_heap1Stat (char * name, int field1, long field2);
/*
Abort if the stack has overflowed.
*/
void
env_checkStack (void)
{
if (env_stackPtr() <= env_stackLimit()) {
fatal(es("env_checkStack: stack overflow"));
}
}
/*
Dump all Macintosh heap blocks.
*/
/*
Define the structure of heap block headers.
*/
#define M_TAG_MASK 0xC0000000 /* Tag field of block_word1. */
#define M_RELOC_BIT 0x80000000 /* Relocatable bit. */
#define M_NRELOC_BIT 0x40000000 /* Non-relocatable bit. */
#define M_UNUSED_BITS 0x30000000 /* Unused bits. */
#define M_CORRECT_MASK 0x0f000000 /* Size correction field. */
#define M_SIZE_MASK 0x00ffffff /* Physical block size. */
typedef struct m_blk_struct m_blk;
static struct m_blk_struct {
unsigned long m_blk_word1;
unsigned long m_blk_word2;
};
/*
Define the structure of master pointers.
*/
/* See page II-25 */
#define MP_LOCK 0x80000000 /* Locked bit. */
#define MP_PURGE 0x40000000 /* Purgeable bit. */
#define MP_RESOURCE 0x20000000 /* Resource bit. */
#define MP_ADDR 0x1fffffff /* Address */
/*
Checksum all 'CODE' blocks in the heap.
Abort if a problem is found.
*/
void
env_checkCode(void)
{
register code_info * new_info;
register code_info * old_info;
if (old_code_info_list == NULL) {
old_code_info_list= env_checkSum();
}
else {
new_code_info_list = env_checkSum();
for (old_info = old_code_info_list; old_info; old_info = old_info -> next) {
for (new_info = new_code_info_list; new_info; new_info = new_info -> next) {
if (env_compare(new_info, old_info) != NULL) {
break;
}
}
}
old_code_info_list = new_code_info_list;
}
}
/*
Compare the checksums of n and search_info.
Abort if they do not match.
*/
static void *
env_compare(code_info * n1, code_info * n2)
{
FTAG("env_compare");
if (n1 -> code_ID != n2 -> code_ID) {
return NULL;
}
if (n1 -> code_checkSum != n2 -> code_checkSum) {
fatal(es("Checksum error: 'CODE' id: "); eint(n1 -> code_ID));
}
if (n1 -> code_tag != n2 -> code_tag) {
;
}
if (n1 -> code_addr != n2 -> code_addr) {
;
}
return n1;
}
static code_info *
env_checkSum (void)
{
Zone * z = ApplZone;
char * zp = (char *) ApplZone;
m_blk * b; /* Ptr to current block header. */
char * p; /* char Ptr to block header. */
m_blk * b_last; /* Ptr to zone trailer block. */
char * mp_addr; /* Address of master pointer. */
register long val;
register long physical_size;
/*
Step 1: Create a list of all 'CODE' blocks.
'CODE' blocks are identified by their ID fields.
*/
b_last = (m_blk *) z -> bkLim;
p = (char *) &(z -> heapData);
while (p < (char *) b_last) {
/* Get the tag field. */
b = (m_blk *) p;
physical_size = (b -> m_blk_word1) & M_SIZE_MASK;
val = (b -> m_blk_word1) & M_TAG_MASK;
if (val & M_RELOC_BIT) {
/* Relocatable block. */
mp_addr = zp + b -> m_blk_word2;
/* Get the master pointer. */
val = *( (long *) mp_addr);
if (val & MP_RESOURCE) {
short theID;
Str255 name;
ResType theType;
/*
Since the master pointer is in the reference list for a
resource we can get the reference information.
*/
GetResInfo( (Handle) mp_addr, &theID, &theType, (pstring) &name);
if (ResError() != resNotFound && theType == 'CODE') {
/* Add the block to the code list. */
}
}
}
p += physical_size;
}
if (p != (char *) b_last) {
fatal(es("env_checkCode: Misalligned heap zone"));
}
/* Step 2: Compute and compare checksums. */
/* Dummy for testing */
return NULL;
}
/*
Calculate and print the heap statistics.
Warning: printing these statistics will likely change the heap!
*/
void
env_heapStat(void)
{
Zone * z = ApplZone;
char * zp = (char *) ApplZone;
m_blk * b; /* Ptr to current block header. */
char * p; /* char Ptr to block header. */
m_blk * b_last; /* Ptr to zone trailer block. */
char * mp_addr; /* Address of master pointer. */
register long val;
register long physical_size;
int total = 0;
int tot_rel = 0;
int tot_nrel = 0;
int tot_free = 0;
int tot_lock = 0;
int tot_purge = 0;
long tot_size = 0L;
long rel_size = 0L;
long nrel_size = 0L;
long free_size = 0L;
long lock_size = 0L;
long purge_size = 0L;
b_last = (m_blk *) z -> bkLim;
p = (char *) &(z -> heapData);
while (p < (char *) b_last) {
b = (m_blk *) p;
/* Calculate overall statistics. */
physical_size = (b -> m_blk_word1) & M_SIZE_MASK;
total++;
tot_size += physical_size;
val = (b -> m_blk_word1) & M_TAG_MASK;
if (val == 0) {
/* Free block. */
tot_free++;
free_size += physical_size;
}
else if (val & M_NRELOC_BIT && !(val & M_RELOC_BIT)) {
/* Non-relocatable block. */
tot_nrel++;
nrel_size += physical_size;
}
else if (val & M_RELOC_BIT && !(val& M_NRELOC_BIT)) {
/* Relocatable block. */
tot_rel++;
rel_size += physical_size;
mp_addr = zp + b -> m_blk_word2;
/* Get the master pointer. */
val = *( (long *) mp_addr);
/* Print the lock, and purge fields. */
if (val & MP_LOCK) {
tot_lock++;
lock_size += physical_size;
}
else if (val & MP_PURGE) {
tot_purge++;
purge_size += physical_size;
}
}
/* Point at the next block. */
p += physical_size;
}
if (p != (char *) b_last) {
es("\nWarning: misalligned heap zone.\n");
}
es("Totals for application heap:\n\n");
eblanks(30);
es("Blocks Logical Block Sizes\n");
env_heap1Stat("Free", tot_free, free_size);
env_heap1Stat("Nonrelocatable", tot_nrel, nrel_size);
env_heap1Stat("Relocatable", tot_rel, rel_size);
env_heap1Stat(" Locked", tot_lock, lock_size);
env_heap1Stat(" Purgeable and not locked", tot_purge, purge_size);
env_heap1Stat("Heap Totals", total, tot_size);
}
static void
env_heap1Stat(char * name, int field1, long field2)
{
epads(name, -30); epadint(field1, 6);
eblanks(4); epadhex(field2, 8); es(" = "); epadlong(field2, 8);
enl();
}
/*
dump the heap.
Printing to the Sherlock window can cause the heap to move!
(sl_line_out calls DrawText, which can move the heap.)
Thus, we must check z -> bkLim after every iteration.
*/
void
env_dumpHeap(void)
{
Zone * z = ApplZone;
char * zp = (char *) ApplZone;
m_blk * b; /* Ptr to current block header. */
char * p, *p2; /* char Ptr to block header. */
m_blk * b_last; /* Ptr to zone trailer block. */
char * mp_addr; /* Address of master pointer. */
register long val;
register long physical_size;
register long logical_size;
int total = 0;
int tot_rel = 0;
int tot_nrel = 0;
int tot_free = 0;
int tot_lock = 0;
int tot_purge = 0;
long tot_size = 0L;
long rel_size = 0L;
long nrel_size = 0L;
long free_size = 0L;
long lock_size = 0L;
long purge_size = 0L;
b_last = (m_blk *) z -> bkLim;
p = (char *) &(z -> heapData);
es("Displaying the Application Heap\n\n");
es("zone: "); eptr(z);
es(" first: "); eptr(p);
es(" last: "); eptr(b_last);
enl();
es(" Start Length Tag Mstr Ptr Lock Purge Type ID File\n");
while (p < (char *) b_last) {
b = (m_blk *) p;
/* Print the logical start and the logical length. */
physical_size = (b -> m_blk_word1) & M_SIZE_MASK;
logical_size = physical_size - sizeof(m_blk);
total++;
tot_size += physical_size;
/* Print the tag field. */
val = (b -> m_blk_word1) & M_TAG_MASK;
if (val == 0) {
/* Free block. */
tot_free++;
free_size += physical_size;
/*
Writing to the Sherlock window may create lots
of free blocks, and the more we write the more are
created. Do not print free blocks!
*/
}
else if (val & M_NRELOC_BIT && !(val & M_RELOC_BIT)) {
/* Non-relocatable block. */
tot_nrel++;
nrel_size += physical_size;
eblanks(2); eptr(p + sizeof(m_blk));
eblanks(1); elong(logical_size);
eblanks(3); es("N\n");
}
else if (val & M_RELOC_BIT && !(val& M_NRELOC_BIT)) {
/* Relocatable block. */
tot_rel++;
rel_size += physical_size;
mp_addr = zp + b -> m_blk_word2;
eblanks(2); eptr(p + sizeof(m_blk));
eblanks(1); elong(logical_size);
eblanks(3); es("R");
eblanks(3); eptr(mp_addr);
/* Get the master pointer. */
val = *( (long *) mp_addr);
/* Print the lock, and purge fields. */
if (val & MP_LOCK) {
tot_lock++;
lock_size += physical_size;
}
else if (val & MP_PURGE) {
tot_purge++;
purge_size += physical_size;
}
eblanks(4); es((val & MP_LOCK) ? "L" : " ");
eblanks(4); es((val & MP_PURGE) ? "P" : " ");
if (val & MP_RESOURCE) {
short theID;
Str255 name;
ResType theType;
char * type = (char *) &theType;
/*
Since the master pointer is in the reference list for a
resource we can get the reference information.
*/
GetResInfo( (Handle) mp_addr, &theID, &theType, (pstring) &name);
if (ResError() == resNotFound) {
es("resNotFound");
}
else {
eblanks(4);
echar(type[0]); echar(type[1]);
echar(type[3]); echar(type[4]);
eblanks(3); epadhex(theID, 4);
eblanks(1); epstring((char *) name);
}
}
/* Make sure the heap doesn't move till here. */
enl();
}
else {
es("BAD TYPE\n");
}
/*
The newline will result in a line being output.
It may also result in the heap being moved.
*/
/*
Point at the next block beyond the current block.
This is *quite* tricky since the heap may have moved
since p was computed.
*/
p2 = (char *) &(z -> heapData);
while (p2 <= p && p2 < (char *) b_last) {
b = (m_blk *) p2;
p2 += ((b -> m_blk_word1) & M_SIZE_MASK);
}
p = p2;
}
if (p != (char *) b_last) {
es("\nWarning: misalligned heap zone.\n");
}
else {
es("\nZone trailer: "); eptr(p); enl();
}
es("\nTotals for application heap:\n");
eblanks(30);
es("Blocks Logical Block Sizes\n");
env_heap1Stat("Free", tot_free, free_size);
env_heap1Stat("Nonrelocatable", tot_nrel, nrel_size);
env_heap1Stat("Relocatable", tot_rel, rel_size);
env_heap1Stat(" Locked", tot_lock, lock_size);
env_heap1Stat(" Purgeable and not locked", tot_purge, purge_size);
env_heap1Stat("Heap Totals", total, tot_size);
}
char *
env_a5 (void)
{
register char * a5_p = 0;
asm {
movea.l a5, a5_p
}
return a5_p;
}
char *
env_stackLimit (void)
{
return (char *) GetApplLimit();
}
long
env_stackMargin(void)
{
return env_stackPtr() - env_stackLimit();
}
char *
env_stackPtr (void)
{
register char * stack_p = 0;
asm {
movea.l sp, stack_p
}
return stack_p;
}
#endif /* THINK_C */
/*
Only this dummy routine is defined if THINK_C is not #define'd.
*/
void
env_dump_stats(void)
{
#if defined(THINK_C)
env_heapStat();
#endif
}